package com.onpositive.dataminer.core;

import java.util.ArrayList;
import java.util.Collection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.onpositive.semantic.model.api.meta.BaseMeta;

public class PropertyMetaPersistance {

	public Document tranformToDoc(Collection<BaseMeta> meta) {
		try {
			DocumentBuilder newDocumentBuilder = DocumentBuilderFactory
					.newInstance().newDocumentBuilder();
			Document newDocument = newDocumentBuilder.newDocument();
			Element createElement = newDocument.createElement("properties");
			for (BaseMeta m : meta) {
				Element createElement2 = newDocument.createElement("property");
				encodeMeta(createElement2, m);
				createElement.appendChild(createElement2);
			}
			newDocument.appendChild(createElement);
			return newDocument;
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	public Collection<BaseMeta> metas(Document dm) {
		NodeList elementsByTagName = dm.getDocumentElement()
				.getElementsByTagName("property");
		ArrayList<BaseMeta> mm = new ArrayList<BaseMeta>();
		for (int a = 0; a < elementsByTagName.getLength(); a++) {
			Element el = (Element) elementsByTagName.item(a);
			BaseMeta meta = new BaseMeta();
			decodeMeta(meta, el);
			mm.add(meta);
		}
		return mm;
	}

	public void encodeMeta(Element elemet, BaseMeta meta) {
		Collection<Object> declaredKeys = meta.declaredKeys();
		for (Object o : declaredKeys) {
			String ac = o.toString();
			Object singleValue = meta.getSingleValue(ac, Object.class, null);
			if (singleValue == null) {
				elemet.setAttribute(ac, "null");
				continue;
			}
			if (singleValue instanceof Boolean) {
				elemet.setAttribute(ac, singleValue.toString());
				continue;
			}
			if (singleValue instanceof Number) {
				elemet.setAttribute(ac, singleValue.toString());
				continue;
			}
			if (singleValue instanceof String[]) {
				Element createElement = elemet.getOwnerDocument()
						.createElement(ac);
				elemet.appendChild(createElement);
				String[] vl = (String[]) singleValue;
				for (String s : vl) {
					Element createElement2 = createElement.getOwnerDocument()
							.createElement("string");
					createElement2.setAttribute("value", s);
					createElement.appendChild(createElement2);
				}
				continue;
			}
			elemet.setAttribute(ac, singleValue.toString());
		}
	}

	public void decodeMeta(BaseMeta meta, Element element) {
		NamedNodeMap attributes = element.getAttributes();
		int length = attributes.getLength();
		NodeList childNodes = element.getChildNodes();
		for (int a = 0; a < childNodes.getLength(); a++) {
			Node item = childNodes.item(a);
			if (item instanceof Element) {
				Element el = (Element) item;
				String nodeName = el.getNodeName();
				NodeList childNodes2 = el.getChildNodes();
				ArrayList<String> str = new ArrayList<String>();
				for (int i = 0; i < childNodes2.getLength(); i++) {
					Node item2 = childNodes2.item(i);
					if (item2 instanceof Element) {
						String attribute = ((Element) item2)
								.getAttribute("value");
						str.add(attribute);
					}
				}
				meta.putMeta(nodeName, str.toArray(new String[str.size()]));
			}
		}
		for (int a = 0; a < length; a++) {
			Node item = attributes.item(a);
			String nodeName = item.getNodeName();
			String nodeValue = item.getNodeValue();
			if (nodeValue.equals("null")) {
				meta.putMeta(nodeName, null);
				continue;
			}
			if (nodeValue.equals("true")) {
				meta.putMeta(nodeName, true);
				continue;
			}
			if (nodeValue.equals("false")) {
				meta.putMeta(nodeName, false);
				continue;
			}
			try {
				int parseInt = Integer.parseInt(nodeValue);
				meta.putMeta(nodeName, parseInt);
				continue;
			} catch (Exception e) {
				try {
					double parseInt = Double.parseDouble(nodeValue);
					meta.putMeta(nodeName, parseInt);
					continue;
				} catch (Exception ex) {
					// TODO: handle exception
				}
			}
			meta.putMeta(nodeName, nodeValue.toString());
		}
	}
}
